﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;
using TeamsPortal.Web.Extensions;
using System.Text;

namespace TeamsPortal.Web.Extensions
{
    public static class PagerExtensions
	{
		#region HtmlHelper extensions

		public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, string labelPrevious, string labelNext)
		{
            return Pager(htmlHelper, pageSize, currentPage, totalItemCount, pagesNearCurrent, null, null, labelPrevious, labelNext);
		}

		public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, string actionName, string labelPrevious, string labelNext)
		{
            return Pager(htmlHelper, pageSize, currentPage, totalItemCount, pagesNearCurrent, actionName, null, labelPrevious, labelNext);
		}

		public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, object values, string labelPrevious, string labelNext)
		{
            return Pager(htmlHelper, pageSize, currentPage, totalItemCount, pagesNearCurrent, null, new RouteValueDictionary(values), labelPrevious, labelNext);
		}

		public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, string actionName, object values, string labelPrevious, string labelNext)
		{
            return Pager(htmlHelper, pageSize, currentPage, totalItemCount, pagesNearCurrent, actionName, new RouteValueDictionary(values), labelPrevious, labelNext);
		}

		public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, RouteValueDictionary valuesDictionary, string labelPrevious, string labelNext)
		{
			return Pager(htmlHelper, pageSize, currentPage, totalItemCount, pagesNearCurrent, null, valuesDictionary, labelPrevious, labelNext);
		}

		public static MvcHtmlString Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, string actionName, RouteValueDictionary valuesDictionary, string labelPrevious, string labelNext)
		{
			if (valuesDictionary == null)
			{
				valuesDictionary = new RouteValueDictionary();
			}
			if (actionName != null)
			{
				if (valuesDictionary.ContainsKey("action"))
				{
					throw new ArgumentException("The valuesDictionary already contains an action.", "actionName");
				}
				valuesDictionary.Add("action", actionName);
			}
			Pager pager = new Pager(htmlHelper, pageSize, currentPage, totalItemCount, pagesNearCurrent, valuesDictionary, labelPrevious, labelNext);
			return pager.RenderHtml();
		}

		#endregion
	}


	public class Pager
	{
		public string LabelNext
		{
			get;
			set;
		}

		public string LabelPrevious
		{
			get;
			set;
		}

		private HtmlHelper _htmlHelper;
		private readonly int _pageSize;
		private readonly int _currentPage;
		private readonly int _totalItemCount;
		private readonly RouteValueDictionary _linkWithoutPageValuesDictionary;
        private readonly int _pagesNearCurrent = 2;

		public Pager(HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, int pagesNearCurrent, RouteValueDictionary valuesDictionary, string labelPrevious, string labelNext) : this()
		{
			_htmlHelper = htmlHelper;
			_pageSize = pageSize;
			_currentPage = currentPage;
			_totalItemCount = totalItemCount;
			_linkWithoutPageValuesDictionary = valuesDictionary;

			if (labelPrevious != null)
			{
				LabelPrevious = labelPrevious;
			}
			if (labelNext != null)
			{
				LabelNext = labelNext;
			}
		}

		public Pager()
		{
			LabelNext = "Next >>";
			LabelPrevious = "<< Previous";
		}

        public static int CalculatePageNumber(int messagesPerPage, int messageNumber)
        {
            int result = (int)Math.Ceiling((double)messageNumber / messagesPerPage);
            return result;
        }

		public MvcHtmlString RenderHtml()
		{
			int pageCount = (int)Math.Ceiling(_totalItemCount / (double)_pageSize);
			if (pageCount <= 1)
			{
				return null;
			}
			
			var sb = new StringBuilder();

			// Previous
			if (_currentPage > 1)
			{
                sb.Append(GeneratePageLink(LabelPrevious, _currentPage - 1, new { @class = "previous", rel = "prev" }));
			}
			else
			{
				sb.Append("<span class=\"disabled previous\">" + _htmlHelper.Encode(LabelPrevious) + "</span>");
			}

            int start = 1;
            if (_currentPage > _pagesNearCurrent + 1)
            {
                //note: show: 1...
                sb.Append(GeneratePageLink("1", 1, null));
                sb.Append("<span class=\"more\">...</span>");

                start = _currentPage - _pagesNearCurrent;
            }

            int stop = pageCount;
            bool showEllipses = (pageCount - _currentPage) > _pagesNearCurrent + 1;
            if (showEllipses)
            {
                stop = _currentPage + _pagesNearCurrent;
            }

            //note: show: 7 8 Curr 10 11
            for (int i = start; i <= stop; i++)
            {
                if (i == _currentPage)
                {
                    sb.AppendFormat("<span class=\"current\">{0}</span>", i);
                }
                else
                {
                    sb.Append(GeneratePageLink(i.ToString(), i, null));
                }
            }
            if (showEllipses)
            {
                //note: show: ... 100
                sb.Append("<span class=\"more\">...</span>");
                sb.Append(GeneratePageLink(pageCount.ToString(), pageCount, null));
            }

			// Next
			if (_currentPage < pageCount)
			{
                sb.Append(GeneratePageLink(LabelNext, (_currentPage + 1), new { @class = "next", rel = "next" }));
			}
			else
			{
				sb.Append("<span class=\"disabled next\">" + _htmlHelper.Encode(LabelNext) + "</span>");
			}
			sb.Insert(0, "<div class=\"pager\">");
			sb.Append("</div>");

			return MvcHtmlString.Create(sb.ToString());
		}

		private MvcHtmlString GeneratePageLink(string linkText, int pageIndex, object htmlAttributes)
		{
			RouteValueDictionary values = new RouteValueDictionary(_htmlHelper.ViewContext.RouteData.Values);
			values.Remove("action");
			values.Remove("controller");
			values["page"] = pageIndex;
			foreach (KeyValuePair<string, object> keyPair in _linkWithoutPageValuesDictionary)
			{
				if (!values.ContainsKey(keyPair.Key))
				{
					values.Add(keyPair.Key, keyPair.Value);
				}
			}

			return _htmlHelper.ActionLink(linkText, 
                _htmlHelper.ViewContext.RouteData.Values["action"].ToString(), 
                _htmlHelper.ViewContext.RouteData.Values["controller"].ToString(), 
                values, 
                new RouteValueDictionary(htmlAttributes));
		}
	}
}
